import os
#os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'  

#import the stubs, i.e. the fake datastore, user and mail service and urlfetch
from google.appengine.api import apiproxy_stub_map
from google.appengine.api import datastore_file_stub
from google.appengine.api import mail_stub
from google.appengine.api import urlfetch_stub
from google.appengine.api import user_service_stub

from google.appengine.api import users

# import the Django Forms replacement provided by the App Engine SDK, 
# so that Django Forms get Data Store model support.
 
from google.appengine.ext.db.djangoforms import ModelForm 

# I use Python Mocker to create mock objects: http://labix.org/mocker
import mocker
from mocker import MockerTestCase
import views
import models
from views import address # importing our view
from models import Address # importing our Model



class TestStart(MockerTestCase):
    
    def setUp(self):

        # Start with a fresh api proxy.
        apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap()

        # Use a fresh stub datastore.
        # From this point on in the tests, all calls to the Data Store, such as get and put,
        # will be to the temporary, in-memory datastore stub. 
        
        stub = datastore_file_stub.DatastoreFileStub(u'myTemporaryDataStorage', '/dev/null', '/dev/null')
        apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', stub)

        # Use a fresh stub UserService.
        apiproxy_stub_map.apiproxy.RegisterStub('user', user_service_stub.UserServiceStub())
        os.environ['AUTH_DOMAIN'] = 'gmail.com'
        os.environ['USER_EMAIL'] = 'myself@appengineguy.com' # set to '' for no logged in user 
        os.environ['SERVER_NAME'] = 'fakeserver.com' 
        os.environ['SERVER_PORT'] = '9999' 
        
        

        # Use a fresh urlfetch stub.
        apiproxy_stub_map.apiproxy.RegisterStub('urlfetch', urlfetch_stub.URLFetchServiceStub())

        # Use a fresh mail stub.
        apiproxy_stub_map.apiproxy.RegisterStub('mail', mail_stub.MailServiceStub()) 
        
        # Mock all calls to HttpResponseRedirect
        self.HttpResponseRedirect = self.mocker.replace("django.http.HttpResponseRedirect")
        
        # Mock all calls to the render_to_response shortcut
        self.render_to_response = self.mocker.replace("django.shortcuts.render_to_response")



        
        
    def testAddressAddressExists(self):
        
        # If a logged in user navigates directly to /address, 
        # his existing address should be displayed in the form.
        m = self.mocker

        # Create an address for the user.
        sampleAddress = Address(user = users.get_current_user(), name = "John Wayne", addressLine1 = "Banana Street 13", addressLine2 = "Wanana",zip = "55555", city = "Woogaboo City", country = "Oompaloompaland" )
        sampleAddress.put()

        # fake the request and POST, as in the test above, but this time, return None.
        mockRequest = self.mocker.mock()
        mockRequest.POST
        m.result(None)
        
        # This is the function that gets called instead of the real, actual render_to_response. 
        def checkArgumentsOfRenderToResponse(path, params):
            containsCorrectName = (params['form']['name'].as_text().count("John Wayne") == 1)
            self.assert_(containsCorrectName, "name field had incorrect data.")
            
            containsCorrectAddressLine1 = (params['form']['addressLine1'].as_text().count("Banana Street 13") == 1)
            self.assert_(containsCorrectAddressLine1, "address line 1 field had incorrect data.")
            
            containsCorrectAddressLine2  = (params['form']['addressLine2'].as_text().count("Wanana") == 1)
            self.assert_(containsCorrectAddressLine2, "address line 2 field had incorrect data.")
            
            containsCorrectZip = (params['form']['zip'].as_text().count("55555") == 1)
            self.assert_(containsCorrectZip, "zip field had incorrect data.")
            
            containsCorrectCity = (params['form']['city'].as_text().count("Woogaboo City") == 1)
            self.assert_(containsCorrectCity, "city field had incorrect data.")
            
            containsCorrectCountry = (params['form']['country'].as_text().count("Oompaloompaland") == 1)
            self.assert_(containsCorrectCountry, "country field had incorrect data.")
            
            return '<html/>'

        # expect a call to render_to_response. We expect ANY parameters here,  
        # since checkArgumentsOfRenderToResponse will be testing the input.
        self.render_to_response(mocker.ANY, mocker.ANY) 
        
        # forward the render_to_response call to checkArgumentsOfRenderToResponse
        m.call(checkArgumentsOfRenderToResponse) 
        
        #okay, we are done recording our expectations.
        m.replay()

        # call the view!
        address(mockRequest)
        
        retrAddress = Address.all().filter("user = ", users.get_current_user()).get()
        self.assertTrue("Mattias Johansson", retrAddress.name)

    def testAddressNotLoggedInRedirect(self):
        
        # fake the request
        mockRequest = self.mocker.mock()
        
        os.environ['USER_EMAIL'] = '' 
        self.assertTrue(users.get_current_user() == None) # The user is now None
        
        # Expect a redirect to login.
        self.HttpResponseRedirect(users.create_login_url("/address"))
        









        #okay, we are done recording our expectations.
        self.mocker.replay()
        
        # call the view!


        address(mockRequest)
        
    def testAddress(self):

        # setting the mocker to a shorthand variable.
        m = self.mocker 
        
        # Making sure the current user has no address. 
        # This is not necessary for a good unit test, but it makes the test more descriptive.
#        addressOfCurrentUser = Address.all().filter("user = ", users.get_current_user()).get()
#        self.assertTrue(addressOfCurrentUser == None)
        
        # create a fake httprequest.
        mockRequest = self.mocker.mock() 
        # create a fake collection that we will use to fake the POST variables.
        mockPostCollection = self.mocker.mock() 
        
        mockRequest.POST # expect the tested code to call the POST collection
        m.count(1, None) # expect it to call it one or more times 
        m.result(mockPostCollection) #make it return the fake collection
        
        # expect the tested code to get some variables from the faked collection
        mockPostCollection.get("name", None)
        m.result("Mattias Johansson")
        mockPostCollection.get("addressLine1", None)
        m.result("Phat Cool Street 5")
        mockPostCollection.get("addressLine2", None)
        m.result("Park Lane")
        mockPostCollection.get("zip", None)
        m.result("361.12-1")
        mockPostCollection.get("city", None)
        m.result("New York")
        mockPostCollection.get("country", None)
        m.result("Hatland")
        
        #expect the tested code to do a redirect.
        self.HttpResponseRedirect("/profile-was-saved")
        
        # okay, we are done setting up our expectations!
        self.mocker.replay() 

        # call the view!
        address(mockRequest)
        
        #make sure that an Address entity was created and properly saved.
        retrAddress = Address.all().filter("user = ", users.get_current_user()).get()
        self.assertEquals("Mattias Johansson", retrAddress.name) 
        self.assertEquals("Phat Cool Street 5", retrAddress.addressLine1) 
        self.assertEquals("Park Lane", retrAddress.addressLine2) 
        self.assertEquals("361.12-1", retrAddress.zip) 
        self.assertEquals("New York", retrAddress.city) 
        self.assertEquals("Hatland", retrAddress.country) 